package com.acmen.easyapi.parse;

import com.acmen.easyapi.annotation.ReqParam;
import com.acmen.easyapi.factory.impl.DefaultClassAliasFactory;
import com.acmen.easyapi.model.ReqParamNode;
import com.acmen.easyapi.util.*;
import com.acmen.easyapi.validation.ValidatorNoteAppender;
import com.acmen.easyapi.util.*;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
 * 请求参数解释器
 * @author acmen
 */
@Component
public class RequestParamParser extends BaseRequestParser {


    public List<ReqParamNode> createParamNodes(Method method) {
              // 获取方法的参数注解列表
        List<List<Annotation>> parameterAnnotations = AnnotationUtil.getParameterAnnotations(method);
        // 获取方法的参数的泛型类型
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        // 获取方法的参数的普通类型
        Type[] parameterTypes = method.getParameterTypes();
        // 获取方法的参数名称
        String[] parameterNames = ParamNameDiscoverer.getParameterNames(method);
        // 创建参数节点列表
        List<ReqParamNode> paramNodes = new ArrayList<ReqParamNode>();
        // 如果参数列表为空，则直接返回参数节点列表
        if (genericParameterTypes.length == 0) {
            return paramNodes;
        }
        // 遍历参数列表
        for (int i=0;i<genericParameterTypes.length;i++) {
            // 检查是否存在 RequestHeader 注解
            RequestHeader requestHeader = AnnotationUtil.getAnnotation(parameterAnnotations.get(i), RequestHeader.class);
            // 检查是否存在 PathVariable 注解
            PathVariable pathVar = AnnotationUtil.getAnnotation(parameterAnnotations.get(i),PathVariable.class);
            // 检查是否存在 RequestBody 注解
            RequestBody requestBody = AnnotationUtil.getAnnotation(parameterAnnotations.get(i), RequestBody.class);
            // 如果存在 RequestHeader、PathVariable 或 RequestBody 注解，则跳过当前参数
            if(requestHeader!=null||pathVar!=null||requestBody!=null){
                continue;
            }
            // 获取当前参数的普通类型
            Type parameterType = parameterTypes[i];
            // 检查是否存在 RequestParam 注解
            RequestParam requestParam = AnnotationUtil.getAnnotation(parameterAnnotations.get(i), RequestParam.class);
            // 如果存在 RequestParam 注解
            if(requestParam!=null){
                // 创建参数节点
                Deprecated deprecated = AnnotationUtil.getAnnotation(parameterAnnotations.get(i), Deprecated.class);
                ReqParamNode paramNode = new ReqParamNode();
                // 如果 RequestParam 中指定了 value，则使用 value 作为参数名称，否则使用 name 作为参数名称
                String paramName = StringUtil.isEmpty(requestParam.value()) ? requestParam.name() : requestParam.value();
                // 如果参数名称为空，则使用方法的参数名称作为参数名称
                if(StringUtil.isEmpty(paramName)){
                    paramName = parameterNames[i];
                }
                paramNode.setName(paramName);
                paramNode.setDeprecated(deprecated!=null);
                paramNode.setType(parameterType.getTypeName());
                paramNode.setTypeAlias(DefaultClassAliasFactory.getAlias(parameterType));
                paramNode.setLabel(requestParam.name());
                // 如果 RequestParam 中的 required 属性为真，则设置参数节点的 required 属性为真
                if(requestParam.required()){
                    paramNode.setRequired(true);
                }
                // 如果参数类型为枚举类型
                if (parameterType instanceof Class) {
                    Class parameterClass = (Class)parameterType;
                    // 如果参数类型为枚举类型，则获取枚举值对应的字典列表
                    if (parameterClass.isEnum() ) {
                        paramNode.setDictionaries(DictionaryUtil.getDictsFromEnum2(parameterClass));
                    }
                }

                // 检查是否存在 ReqParam 注解
                ReqParam reqParam = AnnotationUtil.getAnnotation(parameterAnnotations.get(i), ReqParam.class);
                // 如果存在 ReqParam 注解
                if(reqParam != null){
                    // 如果 ReqParam 中的 required 属性为真，则设置参数节点的 required 属性为真
                    if(reqParam.required()){
                        paramNode.setRequired(true);
                    }
                    paramNode.setLabel(reqParam.label());
                    paramNode.setExample(reqParam.example());

                    // 如果 ReqParam 中的 dictType 属性不为空，则设置参数节点的 dictType 属性为 dictType 的值
                    if(StringUtil.isNotEmpty(reqParam.dictType())){
                        paramNode.setDictType(reqParam.dictType());
                    // 如果 ReqParam 中的 enumClass 属性为枚举类型，则获取枚举值对应的字典列表
                    }else if(reqParam.enumClass().isEnum()){
                        paramNode.setDictionaries(DictionaryUtil.getDictsFromEnum(reqParam.enumClass()));
                    }
                    paramNode.setNotes(getNotes(reqParam));

                    // 字符长度限制
                    if(reqParam.maxLength()>0){
                        paramNode.setMaxLength(reqParam.maxLength());
                    }
                    // 数字最大限制
                    if(reqParam.max()<Long.MAX_VALUE){
                        paramNode.setMax(reqParam.max());
                    }
                    // 数字最小限制
                    if(reqParam.min()>-Long.MAX_VALUE){
                        paramNode.setMin(reqParam.min());
                    }
                    // 校验表达式
                    paramNode.setValidateExp(reqParam.validateExp());

                    paramNode.setRequiredGroup(reqParam.requiredGroup());
                }
                // 将参数节点添加到参数节点列表中
                paramNodes.add(paramNode);
            }else if (ClassUtil.isDtoType(parameterType)) {
                // 如果controller方法中有DTO类，则从DTO类中解释生成文档
                Type genericType = genericParameterTypes[i];
                // 解析DTO类的参数节点列表，并添加到参数节点列表中
                paramNodes.addAll((List)createParamNodes(genericType, new HashMap<>()));
            }
        }

        return paramNodes;
    }

    protected List<String> getNotes(ReqParam param) {
        List<String> notes = new ArrayList<>();
        if(StringUtil.isNotEmpty(param.note())){
            notes.add(param.note());
        }
        if(StringUtil.isNotEmpty(param.validateExp())){
            ValidatorNoteAppender noteAppender = SpringContextUtil.getBean(ValidatorNoteAppender.class);
            if(noteAppender!=null){
                String validateNote = noteAppender.getNote(param.validateExp());
                if(StringUtil.isNotEmpty(validateNote)){
                    notes.add(validateNote);
                }
            }
        }




        return notes;
    }
}
